AWS Fault Injection Service(FIS) でElastiCache をフェイルオーバーさせてみた
こんにちは、なおにしです。
ElastiCache for Valkey(非クラスターモード)のマルチAZ構成に対して、AWS Fault Injection Service を使用してAZ停電シナリオによるフェイルオーバーを試してみたのでご紹介します。
はじめに
AWS Fault Injection Service (FIS)は、サポートされるリソースに対してフォールトインジェクション実験(意図的に誤動作/障害を引き起こす事象を稼働中システムに対して注入する手法)を実行できるようにするマネージドサービスです。
FIS では「アクション」と「ターゲット」の組み合わせによる「実験テンプレート」を作成し、作成した「実験テンプレート」を実行することで対象のAWSリソースに対してフォールトインジェクションを行うことができます。
- アクション:FISによってシミュレートされる意図的な誤動作/障害
- ターゲット:アクションの適用先となるAWSリソース
したがって、標題の内容をFISの用語で表現すると、「AZ停電をシミュレートするアクションをElastiCache for Valkey のレプリケーショングループというターゲットに対して適用する実験テンプレートを実行してみた」という形になります。
ElastiCache のAZ停電をシミュレートするアクションは、ドキュメントでは2023年11月30日に追記されています。
aws:elasticache:interrupt-cluster-az-power アクションが使用できるようになりました。
上記はre:Invent 2023 で追加されたアクションの一部です。その他に追加されたアクションは以下の記事もご参照ください。
アクションの一覧はリファレンスとして以下のドキュメントにまとまっています。
本記事でFISのターゲットとした ElastiCache for Valkey レプリケーショングループは非クラスターモードです。クラスターモードについては以下の記事をご参照ください。
上記の記事に記載されている以外にも、クラスターモードが有効な環境では一部の機能・コマンドの利用が制限されていたりします。
例えば、DBを切り替えるためのSELECTコマンドやKeyを全て削除するFLUSHALLコマンドなどは、実際に実行すると以下のようにエラーが発生します。
# src/valkey-cli -h clustercfg.fis-test-cluster.rio5xr.apne1.cache.amazonaws.com --tls -p 6379
clustercfg.fis-test-cluster.rio5xr.apne1.cache.amazonaws.com:6379> SELECT 1
(error) ERR SELECT is not allowed in cluster mode
clustercfg.fis-test-cluster.rio5xr.apne1.cache.amazonaws.com:6379> FLUSHALL
(error) READONLY You can't write against a read only replica.
また、特に注意が必要なのは実行したコマンドに対応するハッシュスロットが別ノードにある場合、コマンドを別ノードで処理する必要があるため、以下のようにエラーが発生します。
# src/valkey-cli -h clustercfg.fis-test-cluster.rio5xr.apne1.cache.amazonaws.com --tls -p 6379 set hoge 1
(error) MOVED 10439 fis-test-cluster-0001-001.fis-test-cluster.rio5xr.apne1.cache.amazonaws.com:6379
上記の対応方法については以下の記事をご参照ください。
したがって、拡張性などを考慮した上で必要なノード数が1シャードで十分な場合以外にも、クライアント(アプリ)側で上記のとおりクラスターモードの特性に対応していない場合は非クラスターモードも選択肢になり得るかと思います。そうなった場合に可用性を担保するのであれば、非クラスターモードでマルチAZ構成という形になります。
というわけで前置きが長くなりましたが、実際にやってみます。
やってみた
以下のとおり2ノードで構成されるElastiCache for Valkey レプリケーショングループ(非クラスターモード)に対してFISの実験を適用します。
FISによって片方のAZに対してフォールトインジェクションを適用してプライマリノードがフェイルオーバーされること、およびプライマリエンドポイントの向き先がフェイルオーバー先のノードに切り替わったことを確認します。
ElastiCache for Valkey のクラスター情報は以下のとおりです。
それではFISの設定をしていきます。実験テンプレートを1から作成する場合は[実験テンプレートを作成]から操作しますが、各種パラメータの定義をある程度割愛するために、今回はシナリオライブラリで準備されている既存の実験テンプレートから、目的のアクションだけを実行するように削る形でやってみます。
今回使用するアクション「aws:elasticache:interrupt-cluster-az-power」はシナリオライブラリ内の「AZ の可用性:電源の中断」に含まれていますので、こちらのシナリオを選択して実験テンプレートの作成を開始します。
以下のステップごとに設定を進めていきます。[名前]のオプションはNameタグを指していますので、AWSマネジメントコンソールを日本語で使用されている場合はこのタイミングで修正しておかないと後でエラーが出ます。
「AZ の可用性:電源の中断」シナリオでは以下のアクション・ターゲットが設定されている状態になっています。各種リソースに対して「AZ の可用性:電源の中断」を適用するテンプレートになっていますので、今回対象とする「aws:elasticache:interrupt-cluster-az-power」以外のアクションとターゲットを各カードの右上のアイコン(余談ですが「ケバブメニュー」というらしいです)から削除します。
「aws:elasticache:interrupt-cluster-az-power」だけの状態にしました。アクションを編集してみます。
デフォルトの実行時間(Duration)が30分になっていたので、こちらを5分に変更します。FISはアクション 1 分あたり 0.10 ドルの料金となっていますので、複数アクションを長時間実行すると思った以上に請求が発生する可能性があるためご注意ください。
続いてターゲット側を[編集]から開いてみます。以下は特に何も変更していない状態ですので、こちらからターゲット(今回はElastiCache for Valkey のレプリケーショングループ)に設定すべきタグ情報と、対象のAZを確認できます。特に何も変更せずに閉じます。
続いてアクセス許可の設定です。初めてFISを操作する場合は新規にIAMロールを作成します。
オプション設定では停止条件やログ送信に関する内容を追加できます。[レポート設定]については以下の記事をご参照ください。
内容を確認して問題なければ[実験テンプレートを作成]を押して完了します。
停止条件を指定していない場合、以下のように警告が出力されるようです。
以下のように実験テンプレートが作成されました。
[実験を開始]ボタンをすぐに押したいところですが、フェイルオーバーの状況を確認するために先にクライアント側(EC2)で準備します。
## 各ノードのIPアドレスを確認
[root@ip-172-30-30-233 valkey-8.0.1]# dig fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com +short
172.30.60.164
[root@ip-172-30-30-233 valkey-8.0.1]#
[root@ip-172-30-30-233 valkey-8.0.1]# dig fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com +short
172.30.70.141
## プライマリエンドポイントとリーダーエンドポイントのIPアドレスを確認
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
[root@ip-172-30-30-233 valkey-8.0.1]#
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
## プライマリエンドポイントとリーダーエンドポイントの応答を確認
[root@ip-172-30-30-233 valkey-8.0.1]# src/valkey-cli -h master.fis-test.rio5xr.apne1.cache.amazonaws.com --tls -p 6379 ping
PONG
[root@ip-172-30-30-233 valkey-8.0.1]# src/valkey-cli -h replica.fis-test.rio5xr.apne1.cache.amazonaws.com --tls -p 6379 ping
PONG
したがって、フェイルオーバー前の状態は以下となります。
プライマリエンドポイント | リーダーエンドポイント | |
---|---|---|
エンドポイント名 | master.fis-test.rio5xr.apne1.cache.amazonaws.com | replica.fis-test.rio5xr.apne1.cache.amazonaws.com |
ノード名 | fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com |
IPアドレス | 172.30.60.164 | 172.30.70.141 |
切り替わり時の接続確認は以下の記事と同じやり方で行います。
## タイムゾーンを日本標準時に設定
[root@ip-172-30-30-233]# timedatectl set-timezone Asia/Tokyo
## プライマリエンドポイントに対する応答確認の結果をテキストファイルに継続して出力
[root@ip-172-30-30-233]#nohup bash -c 'while true; do printf "%s | " "$(date)"; src/valkey-cli -h master.fis-test.rio5xr.apne1.cache.amazonaws.com --tls -p 6379 ping; done' >> connect.txt &
準備ができたので今回作成した実験テンプレートから[実験を開始]を押すと、以下のようにタグ付けの確認がありましたが特に設定せずにもう一度[実験を開始]を押して進めます。
以下の警告が出ました。誤って[実験を開始]を押してしまわないためなのか、だいぶ慎重なUIになっています。
正常に開始されました。
ElastiCache for Valkey の画面を確認すると、早速フェイルオーバーが発生して切り替わったことが確認できました。
クライアント側で仕掛けていた接続確認のログからは、実験の開始とほぼ同時刻にプライマリエンドポイントへの接続ができなくなったことが確認できました。
Tue Nov 26 16:08:34 JST 2024 | PONG
Tue Nov 26 16:08:35 JST 2024 | PONG
Tue Nov 26 16:08:35 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:35 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
実験テンプレートのアクションで定義していた実行時間が経過すると、実験のステータスが「Completed」になって完了しました。
しばらくすると、ElastiCache for Valkey のステータスも「Available」になりました。プライマリノードは切り替わったままです。
フェイルオーバー直後に各エンドポイントの名前解決をしてみた結果は以下のとおりです。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]#
したがって、フェイルオーバーした時点で以下の状態になりましたので想定どおりの挙動です。
プライマリエンドポイント | リーダーエンドポイント | |
---|---|---|
エンドポイント名 | master.fis-test.rio5xr.apne1.cache.amazonaws.com | replica.fis-test.rio5xr.apne1.cache.amazonaws.com |
ノード名 | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com |
IPアドレス | 172.30.70.141 | 172.30.70.141 |
レプリケーショングループの設定としてログの取得を有効にしていなくても、以下のとおりイベントにはフェイルオーバーの情報が出力されています。
クライアント側で仕掛けていたログ上でのプライマリエンドポイントの接続断→接続再開のタイミングは以下のとおりです。接続拒否をされていた時間としては「16:08:35」〜「16:08:42」の『7秒間』でした。
しかし、※マークをつけた箇所のタイムスタンプからは、接続再開後の最初の試行で「16:08:42」〜「16:10:55」の『2分13秒』という応答待ちが発生しているようです。この間のどこかのタイミングで新規セッションで受け付けた接続なら応答できた可能性もありますが、今回の確認方法はシリアル実行だったため、少なくともクライアント側でタイムアウト値を設けていない場合はログと同じような挙動になるかもしれません。
[root@ip-172-30-30-233 valkey-8.0.1]# grep -3 "Connection refused" connect.txt | head -6
Tue Nov 26 16:08:34 JST 2024 | PONG
Tue Nov 26 16:08:34 JST 2024 | PONG
Tue Nov 26 16:08:35 JST 2024 | PONG
Tue Nov 26 16:08:35 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:35 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:35 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
[root@ip-172-30-30-233 valkey-8.0.1]#
[root@ip-172-30-30-233 valkey-8.0.1]# grep -3 "Connection refused" connect.txt | tail -6
Tue Nov 26 16:08:42 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:42 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:42 JST 2024 | Could not connect to Valkey at master.fis-test.rio5xr.apne1.cache.amazonaws.com:6379: Connection refused
Tue Nov 26 16:08:42 JST 2024 | PONG ※
Tue Nov 26 16:10:55 JST 2024 | PONG ※
Tue Nov 26 16:10:55 JST 2024 | PONG
[root@ip-172-30-30-233 valkey-8.0.1]#
また、イベント画面の「16:24:16」のメッセージ「Finished recovery for cache nodes 0001」のタイミングで、FISによって適用されたフォールトインジェクションに対するリカバリが完了している状態になったことが分かります。FISの実験テンプレートの終了時刻は「16:13:33」になっていたので、ステータスとして完全にリカバリされるまでには10分ほどかかった結果となりました。
その後に先ほどと同様にプライマリエンドポイントとリーダーエンドポイントの向き先を確認すると、ノード1に対する処理が再開されていることも確認できました。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
[root@ip-172-30-30-233 valkey-8.0.1]#
プライマリエンドポイント | リーダーエンドポイント | |
---|---|---|
エンドポイント名 | master.fis-test.rio5xr.apne1.cache.amazonaws.com | replica.fis-test.rio5xr.apne1.cache.amazonaws.com |
ノード名 | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com | fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com. |
IPアドレス | 172.30.70.141 | 172.30.60.164 |
もう一度実験テンプレートを開始してみる
フェイルオーバーが発生してプライマリノードが入れ替わった状態で再度実験テンプレートを開始してみます。フォールトインジェクションを適用する対象は変わらずノード1になりますので、今回はレプリカノードに対して障害が発生した場合のシナリオとなります。
各ノードのステータスが「Modifying」に変わりました。
プライマリエンドポイントへの接続不可は発生することなく、リーダーエンドポイントの向き先が現在のプライマリノード(ノード2)に切り替わりました。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
プライマリエンドポイント | リーダーエンドポイント | |
---|---|---|
エンドポイント名 | master.fis-test.rio5xr.apne1.cache.amazonaws.com | replica.fis-test.rio5xr.apne1.cache.amazonaws.com |
ノード名 | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com | fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com |
IPアドレス | 172.30.70.141 | 172.30.70.141 |
実験テンプレートも問題なく完了しました。
ElastiCache 側も各ノードのステータスが「Available」に変わりました。
今回はフェイルオーバーが発生しないため、イベントとしては「Recovering cache nodes 0001」から出力が始まっています。
イベント出力が上記の状態のタイミングではまだリーダーエンドポイントの向き先はプライマリノード(ノード2)となっています。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
イベント画面に再度ノード1をリカバリ中である旨のメッセージが出力されました。
上記のタイミングでリーダーエンドポイントがレプリカノード(ノード1)に切り替わったようです。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
その後、リカバリ終了のメッセージが出力されました。
フェイルバックする
FISの実行前の状態と比較してプライマリノードとレプリカノードが入れ替わったまま(= フェイルオーバーしたまま)の状態なので、フェイルバックさせます。ElastiCache for Valkey の画面からノード2を選択して[プライマリをフェイルオーバー]を押します。
画面上はすぐに各ノードのステータスが「Available」になりましたが、プライマリエンドポイントへの接続不可はフォールトインジェクションを適用した際と同様に発生しました。
ノード2をフェイルオーバーさせているので、一旦はプライマリエンドポイントとリーダーエンドポイントの両方がノード1を向きます。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
イベント時刻としては以下の流れで推移しました。手動でフェイルオーバーさせた場合でもリカバリの完了がイベントとして登録されるまでには10分ほどかかりました。
フェイルオーバー自体は数十秒で完了しますが、各エンドポイントがそれぞれのノードで使用できる状態になるまではもう少しかかるという印象です。少なくとも上記のイベントが発生した後であれば、プライマリエンドポイントとリーダーエンドポイントは最初の実験テンプレート開始前の状態に戻っています。
[root@ip-172-30-30-233 valkey-8.0.1]# dig master.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-001.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.60.164
[root@ip-172-30-30-233 valkey-8.0.1]# dig replica.fis-test.rio5xr.apne1.cache.amazonaws.com +short
fis-test-002.fis-test.rio5xr.apne1.cache.amazonaws.com.
172.30.70.141
補足
マルチAZが有効になっていないレプリケーショングループに対して実験を適用した場合
以下のとおり実験を開始しても失敗します。
ターゲットにタグを設定していない場合
ターゲットの編集画面で確認したタグをElastiCache for Valkey のレプリケーショングループに設定していないと、実験テンプレートを開始後にすぐに「Skipped」で完了状態になりました。
もし上記のようになった場合はElastiCache for Valkey の設定画面からタグが設定されていることを確認します。
valkey-cliのセットアップ
今回は以下のドキュメントに記載のAmazon Linux 2 用のインストール内容をAL2023に読み替えてインストールしました。
# dnf install gcc jemalloc-devel openssl-devel tcl tcl-devel -y
# wget https://github.com/valkey-io/valkey/archive/refs/tags/8.0.1.tar.gz
# tar xvzf ./8.0.1.tar.gz
# cd valkey-8.0.1/
# make BUILD_TLS=yes
### 動作確認
# src/valkey-cli -h cache-endpoint --tls -p 6379
> set a "hello" // Set key "a" with a string value and no expiration
OK
> get a // Get value for key "a"
"hello"
### make install するとvalkey-server 等まで/usr/local/bin/配下にコピーされるので、必要に応じてvalkey-cliのみコピー
# cp -p src/valkey-cli /usr/local/bin/
まとめ
FISを使ってAZ障害のシミュレーションをElastiCache for Valkey のレプリケーショングループに適用してみました。実際は滅多に発生しない状況かと思いますが、可能であれば障害発生時の挙動を事前に確認しておき、万が一実際に発生した時でも慌てないように準備できていると、復旧措置も迅速に対応できるかと思います。
そもそもそういった管理をしたくないという場合には、クライアント側でクラスターモードに対応できることを確認した上でサーバーレス構成を検討するのも良いかと思いますが、もちろん費用に跳ね返ってくるので難しいところです。
本記事がどなたかのお役に立てれば幸いです。